package distributed

import (
	"context"
	"errors"
	"fmt"
	"time"

	"go.etcd.io/etcd/clientv3"
	"yu.DbPrime/src/config"
	"yu.DbPrime/src/utils"
)

type etcdClass struct {
	Urls        []string         //连接etcd的urls组
	DialTimeout time.Duration    //连接超时时间
	cli         *clientv3.Client //连接句柄
	cli_err     error            //连接的错误信息
}

var etcd *etcdClass

func init() { //单例模式创建一个饿汉式的单例模式的etcdClass类的实例Etcd
	etcd = &etcdClass{ //初始化配置信息
		Urls:        config.EtcdUrls,
		DialTimeout: config.EtcdDialTimeout,
	}
	//连接函数
	etcd.connect()
}
func GetEtcd() *etcdClass {
	return etcd
}

func (e etcdClass) connect() error {

	cli, err := clientv3.New(clientv3.Config{ //cli其实返回的是一个*clientv3的指针类型
		Endpoints:   e.Urls,
		DialTimeout: e.DialTimeout,
	})
	if err != nil {
		fmt.Printf("etcd_连接异常: %v\n", err)
	}
	etcd.cli = cli
	etcd.cli_err = err
	return err
}

func (e etcdClass) Write(title string, value string) error {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	_, err_put := e.cli.Put(ctx, title, value)
	if err_put != nil {
		fmt.Printf("etcd写数据异常: %v\n", err_put)
	}
	return err_put
}

func (e etcdClass) Read(title string) (string, error) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	resp, err_get := e.cli.Get(ctx, title, clientv3.WithPrefix())
	if err_get != nil {
		fmt.Printf("etcd读数据异常: %v\n", err_get)
	}
	if len(resp.Kvs) == 0 {
		return "", errors.New("etcd内没有对应的数据")
	}
	return string(resp.Kvs[0].Value), nil
}

// 这个地方结合工厂模式来说
func (e etcdClass) ReadStruct(title string) (utils.KVFactory, error) {
	str, err := e.Read(title)
	res := utils.CreateClass(title)
	res.UnParse(str)
	return res, err
}

type watchChHandle func(v string)

func (e etcdClass) Watch(title string, w watchChHandle) {
	watchCh := e.cli.Watch(context.TODO(), title, clientv3.WithPrefix())
	for res := range watchCh {
		w(string(res.Events[0].Kv.Value))
		fmt.Printf("res: %v\n", res.Events[0].Kv.Value)
	}
}

func (e etcdClass) Close() {
	e.cli.Close()
}
